package xyz.fivefaith.faithtool.redis;

import org.redisson.Redisson;
import org.redisson.api.RBlockingDeque;
import org.redisson.api.RList;
import org.redisson.api.RQueue;
import org.redisson.api.RScoredSortedSet;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;

import xyz.fivefaith.faithtool.redis.constant.RedisConstant;

import java.io.IOException;
import java.io.InputStream;
import java.time.Duration;
import java.util.Collection;
import java.util.List;
import java.util.Properties;
import java.util.Set;

/**
 * redis工具类
 *
 * @author zhaoanchi
 * @version 1.0
 * @since 1.0
 */
public final class RedisListUtil {
    private static final RedissonClient CLIENT;

    /* ---------- 静态块：加载 redis.properties ---------- */
    static {
        Properties props = new Properties();
        try (InputStream in =
                RedisListUtil.class
                        .getClassLoader()
                        .getResourceAsStream(RedisConstant.REDIS_CONFIG_PATH)) {
            if (in == null) {
                throw new RuntimeException("redis.properties not found in classpath");
            }
            props.load(in);
        } catch (IOException e) {
            throw new RuntimeException("load redis.properties error", e);
        }

        String host = props.getProperty("redis.host", "127.0.0.1");
        int port = Integer.parseInt(props.getProperty("redis.port", "6379"));
        String password = props.getProperty("redis.password");
        int db = Integer.parseInt(props.getProperty("redis.database", "0"));

        Config config = new Config();
        config.useSingleServer().setAddress("redis://" + host + ":" + port).setDatabase(db);
        if (password != null && !password.isBlank()) {
            config.useSingleServer().setPassword(password);
        }

        CLIENT = Redisson.create(config);
    }

    /* ---------- 工具方法 ---------- */

    /** 检查值是否存在 */
    public boolean isExist(String key) {
        return CLIENT.getBucket(key).isExists();
    }

    /* ---------------- 基础 List 操作 ---------------- */

    /** 获取 RList 实例 */
    public <T> RList<T> getList(String key) {
        return CLIENT.getList(key);
    }

    /** 左端插入 */
    public <T> void leftPush(String key, T element) {
        getList(key).add(0, element);
    }

    /** 右端插入 */
    public <T> boolean rightPush(String key, T element) {
        return getList(key).add(element);
    }

    /** 从左端弹出（LPOP） */
    public <T> T leftPop(String key) {
        RList<T> list = getList(key);
        return list.isEmpty() ? null : list.remove(0);
    }

    /** 从右端弹出（RPOP） */
    public <T> T rightPop(String key) {
        RList<T> list = getList(key);
        return list.isEmpty() ? null : list.remove(list.size() - 1);
    }

    /** 根据索引获取 */
    public <T> T index(String key, int index) {
        RList<T> list = getList(key);
        return list.get(index);
    }

    /** 设置索引位置的值 */
    public <T> T set(String key, int index, T element) {
        RList<T> list = getList(key);
        return list.set(index, element);
    }

    /** 移除指定元素 */
    public <T> boolean removeList(String key, T element) {
        return getList(key).remove(element);
    }

    /** 批量插入 */
    public <T> void addAll(String key, Collection<? extends T> c) {
        getList(key).addAll(c);
    }

    /** 列表长度 */
    public int sizeList(String key) {
        RList<Object> list = getList(key);
        return list.size();
    }

    /** 清空列表 */
    public void clearList(String key) {
        getList(key).clear();
    }

    /** 读取所有元素（快照） */
    public <T> List<T> readAll(String key) {
        RList<T> list = getList(key);
        return list.readAll();
    }

    /** 保留区间 [from, to]，其余删除（trim） */
    public void trim(String key, int from, int to) {
        getList(key).trim(from, to);
    }

    /** 为整个 List 设置过期时间 */
    public void expire(String key, Duration duration) {
        getList(key).expire(duration);
    }

    /* ---------------- Queue 快速转换 ---------------- */

    /** 获取阻塞队列（FIFO） */
    public <T> RQueue<T> getQueue(String key) {
        return CLIENT.getQueue(key);
    }

    /** 获取阻塞双端队列 */
    public <T> RBlockingDeque<T> getBlockingDeque(String key) {
        return CLIENT.getBlockingDeque(key);
    }

    /* ===== Set ===== */
    public static <T> void sAdd(String key, T... values) {
        CLIENT.getSet(key).addAll(Set.of(values));
    }

    public static <T> Set<T> sMembers(String key) {
        return CLIENT.getSet(key);
    }

    /* ===== ZSet ===== */
    public static void zAdd(String key, double score, Object member) {
        CLIENT.getScoredSortedSet(key).add(score, member);
    }

    public static <T> Collection<T> zRange(String key, int start, int end) {
        RScoredSortedSet<T> zSet = CLIENT.getScoredSortedSet(key);
        return zSet.valueRange(start, end);
    }

    /* ---------- 其余工具方法保持不变 ---------- */
    public static void shutdown() {
        CLIENT.shutdown();
    }
}
